package cn.com.bluemoon.daps.model.controller;

import cn.com.bluemoon.common.KeyAnnotationClz;
import cn.com.bluemoon.common.UserPermission;
import cn.com.bluemoon.common.permission.ModelEdit;
import cn.com.bluemoon.daps.common.datascope.BmPermission;
import cn.com.bluemoon.daps.common.domain.ResultBean;
import cn.com.bluemoon.daps.common.enums.BmStatus;
import cn.com.bluemoon.daps.common.toolkit.CheckUtils;
import cn.com.bluemoon.daps.model.dto.SimpleFieldDto;
import cn.com.bluemoon.daps.model.dto.SimpleTableDto;
import cn.com.bluemoon.daps.model.dto.TableListDto;
import cn.com.bluemoon.daps.model.entity.*;
import cn.com.bluemoon.daps.model.service.*;
import cn.com.bluemoon.daps.model.vo.ForeignKeyVo;
import cn.com.bluemoon.daps.model.vo.SingleForeignKeyVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import io.swagger.annotations.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@RestController
@Slf4j
@RequestMapping("/model")
@Api(tags = {"模型外键功能"})
public class DapModelForeignController {


    @Resource
    DapDataModelService dapDataModelService;

    @Resource
    DapDataModelTableService dapDataModelTableService;

    @Resource
    DapDataModelTableFieldService dapDataModelTableFieldService;

    @Resource
    DapDataModelTableForeignKeyService dapDataModelTableForeignKeyService;

    @Resource
    DapDataModelShareTableService dapDataModelShareTableService;

    /**
     * 获取外键关系
     * @param tableId
     * @return
     */
    @BmPermission(value = "model:table:modify", name = "编辑模型表")
    @GetMapping("foreign/list")
    @ApiOperation(value = "外键关系列表")
    @ApiResponses(value = {@ApiResponse(code = 200, message = "ok", response = DapDataModelTableForeignKey.class)})
    public ResultBean<List<DapDataModelTableForeignKey>>  foreignKeyList(@RequestParam @ApiParam("tableId") String tableId,
                                                                         @RequestParam @ApiParam("modelId") String modelId){

        // 根据表id获得外键关系
        List<DapDataModelTableForeignKey> tableForeignKeys = dapDataModelTableForeignKeyService.getBaseMapper()
                .selectList(new LambdaQueryWrapper<DapDataModelTableForeignKey>()
                        .eq(DapDataModelTableForeignKey::getModelTableId, tableId)
                        .eq(DapDataModelTableForeignKey::getBmStatus, BmStatus.ON.getCode()));
        // 外键关系为空
        if(tableForeignKeys.isEmpty()){ return ResultBean.ok(null); }
        // 获得该表以及引用表的的字段id
        List<String> fieldIds = tableForeignKeys.stream().flatMap(d -> {
            return Arrays.asList(d.getModelTableFieldId(), d.getReferenceFieldId()).stream();
        }).distinct().collect(Collectors.toList());
        // 查询所有字段信息
        List<DapDataModelTableField> fields = dapDataModelTableFieldService.getBaseMapper().selectBatchIds(fieldIds);
        // 获得该表引用的模型列表
        List<String> modelIds = tableForeignKeys.stream().map(DapDataModelTableForeignKey::getReferenceModelId).distinct().collect(Collectors.toList());
        List<DapDataModel> modelList = dapDataModelService.getBaseMapper().selectBatchIds(modelIds);
        // 获得引用表的列表
        List<String> tableIds = tableForeignKeys.stream().map(DapDataModelTableForeignKey::getReferenceTableId).collect(Collectors.toList());
        List<DapDataModelTable> tables = dapDataModelTableService.getBaseMapper().selectBatchIds(tableIds);
        // 查询模型下的所有表(包括公共模型下的表)
        List<TableListDto> collect = dapDataModelTableService.getList(modelIds);
        // 剔除当前表
        List<TableListDto> modelTableList = collect.stream().filter(t -> !t.getTableId().equals(tableId)).collect(Collectors.toList());
        for (DapDataModelTableForeignKey t : tableForeignKeys) {
            List<SimpleTableDto> objects = new ArrayList<>();
            List<SimpleFieldDto> fieldList = new ArrayList<>();
            for (TableListDto dto : modelTableList){
                if(t.getReferenceModelId().equals(dto.getDataModelId())){
                    SimpleTableDto bean = dto.bean(dto);
                    objects.add(bean);
                    if(dto.getTableId().equals(t.getReferenceTableId())){
                        fieldList = dto.getList(dto.getFieldList());
                    }
                }
            }
            for(DapDataModelTableField f : fields){
                // 外键关系中的字段名
                if (f.getId().equals(t.getModelTableFieldId())) {
                    t.setFieldName(f.getFieldName());
                }
                // 外键关系中的引用字段名
                if (f.getId().equals(t.getReferenceFieldId())) {
                    t.setReferenceFieldName(f.getFieldName());
                }
            }
            // 外键关系中的引用的模型名
            for (DapDataModel m : modelList){
                if (t.getReferenceModelId().equals(m.getId())) {
                    t.setReferenceModelName(m.getName());
                }
            }
            // 外键关系中的表名
            for(DapDataModelTable table : tables){
                if (t.getReferenceTableId().equals(table.getId())) {
                    t.setReferenceTableName(table.getEngName());
                }
            }
            t.setRelationName(t.getFieldName()+"->"+t.getReferenceFieldName()+"("+t.getRelation()+")");
            t.setReferTableList(objects);
            t.setReferFieldList(fieldList);
        }
        return ResultBean.ok(tableForeignKeys);
    }
    @BmPermission(value = "model:table:modify", name = "编辑模型表")
    @PostMapping("add/single/foreign")
    @ApiOperation(value = "新增单条外键关系")
    @ApiResponses(value = {@ApiResponse(code = 200, message = "ok", response = String.class)})
    @UserPermission.SingleRow(keyFormClz = KeyAnnotationClz.RequestBody, errorMsg = "只允许模型授权者编辑外键关系")
    @ModelEdit(keyFormClz = KeyAnnotationClz.RequestBody)
    public ResultBean<String> addSingleKey(@RequestBody SingleForeignKeyVo key){

        DapDataModelTableForeignKey dapDataModelTableForeignKey = new DapDataModelTableForeignKey();
        if(key != null){
            // 新增
            if(StringUtils.isBlank(key.getId())){
                List<DapDataModelTableForeignKey> tableForeignKeys = dapDataModelTableForeignKeyService.getBaseMapper()
                        .selectList(new LambdaQueryWrapper<DapDataModelTableForeignKey>()
                        .in(DapDataModelTableForeignKey::getModelTableId, key.getModelTableId(), key.getReferenceTableId())
                        .in(DapDataModelTableForeignKey::getReferenceTableId, key.getReferenceTableId(), key.getModelTableId())
                        .eq(DapDataModelTableForeignKey::getBmStatus, BmStatus.ON.getCode()));
                if(!tableForeignKeys.isEmpty()){
                    return ResultBean.error("两张表之间已存在外键关系，不允许增加");
                }
                // 进行复制
                BeanUtils.copyProperties(key, dapDataModelTableForeignKey);
                dapDataModelTableForeignKeyService.save(dapDataModelTableForeignKey);
            }
            return ResultBean.ok(dapDataModelTableForeignKey.getId());
        }else{
            return ResultBean.error("请添加外键关系");
        }
    }

    @BmPermission(value = "model:table:modify", name = "编辑模型表")
    @PostMapping("add/foreign")
    @ApiOperation(value = "新增或修改外键关系列表")
    @ApiResponses(value = {@ApiResponse(code = 200, message = "ok", response = Boolean.class)})
    @UserPermission.SingleRow(keyFormClz = KeyAnnotationClz.RequestBody, errorMsg = "只允许模型授权者编辑外键关系")
    @ModelEdit(keyFormClz = KeyAnnotationClz.RequestBody)
    public ResultBean<Boolean> addForeignKey(@RequestBody ForeignKeyVo vo){

        if(!vo.keyList.isEmpty()){
            Map<String, List<DapDataModelTableForeignKey>> map = vo.keyList.stream()
                    .collect(Collectors.groupingBy(DapDataModelTableForeignKey::getModelTableId));
            for (Map.Entry<String, List<DapDataModelTableForeignKey>> entry : map.entrySet()) {
                // 引用表的集合
                List<String> collect = entry.getValue().stream().map(DapDataModelTableForeignKey::getReferenceTableId).collect(Collectors.toList());
                List<String> ids = CheckUtils.getDuplicateElements(collect);
                if(!ids.isEmpty()){
                    return ResultBean.error("参考表名重复");
                }
            }
            return dapDataModelTableForeignKeyService.updateOrInsertKey(vo.keyList);
        }
        return ResultBean.ok(true);
    }

    @BmPermission(value = "model:table:modify", name = "编辑模型表")
    @GetMapping("foreign/field/list")
    @ApiOperation(value = "外键字段列表")
    @ApiResponses(value = {@ApiResponse(code = 200, message = "ok", response = DapDataModelTableField.class)})
    public ResultBean<List<DapDataModelTableField>> foreignKeyFieldList(@RequestParam("tableId") String tableId){

        List<DapDataModelTableField> fields = dapDataModelTableFieldService.getBaseMapper()
                .selectList(new LambdaQueryWrapper<DapDataModelTableField>()
                .eq(DapDataModelTableField::getModelTableId, tableId)
                .eq(DapDataModelTableField::getBmStatus, BmStatus.ON.getCode()));
        return ResultBean.ok(fields);
    }

    @BmPermission(value = "model:table:modify", name = "编辑模型表")
    @GetMapping("foreign/model/list")
    @ApiOperation(value = "外键模型列表(包括公共模型)")
    @ApiResponses(value = {@ApiResponse(code = 200, message = "ok", response = ResultBean.class)})
    public ResultBean<List<DapDataModel>> foreignKeyModelList(@RequestParam("modelId") @ApiParam("模型id") String modelId){

        DapDataModel dapDataModel = dapDataModelService.getBaseMapper().selectById(modelId);
        // 查询共享模型
        List<DapDataModelShareTable> shareModel = dapDataModelShareTableService.getBaseMapper()
                .selectList(new LambdaQueryWrapper<DapDataModelShareTable>()
                .eq(DapDataModelShareTable::getSystemId, dapDataModel.getSystemId()));
        List<DapDataModel> list = new ArrayList<>();
        if(!shareModel.isEmpty()){
            List<String> collect = shareModel.stream().map(DapDataModelShareTable::getModelId).collect(Collectors.toList());
            if(!collect.contains(modelId)){
                collect.add(modelId);
            }
            list = dapDataModelService.getBaseMapper().selectBatchIds(collect);
            return ResultBean.ok(list);
        }
        list.add(dapDataModel);
        return ResultBean.ok(list);
    }

    @BmPermission(value = "model:table:modify", name = "编辑模型表", ignore = true)
    @GetMapping("foreign/table/list")
    @ApiOperation(value = "外键表列表(包括公共模型)")
    @ApiResponses(value = {@ApiResponse(code = 200, message = "ok", response = DapDataModelTable.class)})
    public ResultBean<List<DapDataModelTable>> foreignKeyTableList(@RequestParam("modelId") String modelId,
                                                                   @RequestParam("tableId") String tableId,
                                                                   @RequestParam(value = "name", required = false) String name){
        // 根据表格id获取当前模型id
        DapDataModelTable table = dapDataModelTableService.getBaseMapper().selectById(tableId);
        String currentModelId = table.getDataModelId();
        // 当前模型下的表
        if(currentModelId.equals(modelId)){
            LambdaQueryWrapper<DapDataModelTable> lam = new LambdaQueryWrapper<DapDataModelTable>()
                    .eq(DapDataModelTable::getDataModelId, modelId)
                    .eq(DapDataModelTable::getPId, "0")
                    .eq(DapDataModelTable::getBmStatus, BmStatus.ON.getCode());
            List<DapDataModelTable> tables = dapDataModelTableService.getBaseMapper().selectList(lam);
            // 剔除当前表
            List<DapDataModelTable> collect = tables.stream()
                    .filter(t -> !t.getId().equals(tableId)).collect(Collectors.toList());
            return ResultBean.ok(collect);
        }else{
            // 共享模型表
            List<DapDataModelShareTable> list = dapDataModelShareTableService.getBaseMapper().selectList(new LambdaQueryWrapper<DapDataModelShareTable>()
                    .eq(DapDataModelShareTable::getModelId, modelId));
            List<String> tableIds = list.stream().map(DapDataModelShareTable::getTableId).collect(Collectors.toList());
            List<DapDataModelTable> tableList = new ArrayList<>();
            if(!tableIds.isEmpty()){
                tableList = dapDataModelTableService.getBaseMapper().selectBatchIds(tableIds);
            }
            return ResultBean.ok(tableList);
        }
    }

    @BmPermission(value = "model:table:modify", name = "编辑模型表", ignore = true)
    @GetMapping("reference/field/list")
    @ApiOperation(value = "外键引用字段列表")
    @ApiResponses(value = {@ApiResponse(code = 200, message = "ok", response = DapDataModelTableField.class)})
    public ResultBean<List<DapDataModelTableField>> referenceTableList(@RequestParam("tableId") String tableId){

        // 根据表id获得字段
        List<DapDataModelTableField> fields = dapDataModelTableFieldService.getBaseMapper()
                .selectList(new LambdaQueryWrapper<DapDataModelTableField>()
                .eq(DapDataModelTableField::getModelTableId, tableId)
                .eq(DapDataModelTableField::getBmStatus, BmStatus.ON.getCode()));
        return ResultBean.ok(fields);
    }

    @BmPermission(value = "model:table:modify", name = "编辑模型表", ignore = true)
    @DeleteMapping("reference/delete/foreign")
    @ApiOperation(value = "删除外键")
    @ApiResponses(value = {@ApiResponse(code = 200, message = "ok", response = Boolean.class)})
    @UserPermission.SingleRow(keyFormClz = KeyAnnotationClz.RequestParam, key = "modelId", errorMsg = "只允许模型授权者删除外键关系")
    @ModelEdit(keyFormClz = KeyAnnotationClz.RequestParam, key = "modelId")
    public ResultBean<Boolean> deleteForeignKey(@RequestParam("id") String foreignId,
                                                @RequestParam(value = "modelId") String modelId){
        //如果外键id不是该模型下的
        if(StringUtils.isNotBlank(foreignId)){
            // 查询模型下的外键关系
            DapDataModelTableForeignKey dapDataModelTableForeignKey = dapDataModelTableForeignKeyService.getBaseMapper().selectById(foreignId);
            if(dapDataModelTableForeignKey != null && !dapDataModelTableForeignKey.getModelTableId().equals(modelId)){
                ResultBean.error("该外键关系不属于当前模型，不允许删除！");
            }
        }
        // 根据表id获得字段
        dapDataModelTableForeignKeyService.getBaseMapper().deleteById(foreignId);
        return ResultBean.ok(true);
    }
}
